package com.vijay.extension.spring;

import com.vijay.extension.annotation.SpringExtension;
import com.vijay.extension.annotation.SpringKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;

import java.util.Set;

public class SpringExtensionScanner extends ClassPathBeanDefinitionScanner {


    private static final Logger logger = LoggerFactory.getLogger(SpringExtensionScanner.class);


    private SpringExtensionFactoryBean factoryBean = new SpringExtensionFactoryBean();

    public SpringExtensionScanner(BeanDefinitionRegistry registry) {

        super(registry, false);

        addIncludeFilter((reader, factory) -> {

            ClassMetadata classMetadata = reader.getClassMetadata();

            if (!classMetadata.isInterface() || !classMetadata.isIndependent()) return false;

            if (!AnnotationMetadata.class.isAssignableFrom(classMetadata.getClass())) return false;

            AnnotationMetadata annotationMetadata = AnnotationMetadata.class.cast(classMetadata);

            if (!annotationMetadata.hasAnnotation(SpringExtension.class.getName()) && !annotationMetadata.hasAnnotatedMethods(SpringKey.class.getName()))
                return false;

            return true;

        });


    }

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> holders = super.doScan(basePackages);

        if (holders == null || holders.isEmpty()) {
            logger.warn("No found SpringExtension please check");
        } else {
            processBeanDefinitions(holders);
        }
        return holders;

    }

    private void processBeanDefinitions(Set<BeanDefinitionHolder> holders) {

        GenericBeanDefinition definition;

        for (BeanDefinitionHolder holder : holders) {

            definition = (GenericBeanDefinition) holder.getBeanDefinition();

            //System.out.println(definition.getBeanClassName());

            definition.getPropertyValues().add("extensionInterface", definition.getBeanClassName());

            definition.setBeanClass(factoryBean.getClass());

            definition.setPrimary(true);
        }


    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {

        AnnotationMetadata metadata = beanDefinition.getMetadata();

        return metadata.isInterface() && metadata.isIndependent();
    }
}
